package io.sundial.scheduler.impl;

import io.sundial.coordination.ConnStatus;
import io.sundial.coordination.Coordinator;
import io.sundial.coordination.CoordinatorException;
import io.sundial.coordination.vote.VoteWatcher;
import io.sundial.coordination.watching.EventWatching;
import io.sundial.core.Locker;
import io.sundial.core.context.Context;
import io.sundial.core.event.EventListener;
import io.sundial.core.lifecycle.exception.DestroyingException;
import io.sundial.core.lifecycle.exception.InitializingException;
import io.sundial.engine.exception.ShuttingException;
import io.sundial.engine.exception.StartingException;
import io.sundial.planning.Planner;
import io.sundial.planning.event.PlannedEvent;
import io.sundial.task.Task;

/**
 * 抽象的主动式调度器
 *
 * @author Payne 646742615@qq.com
 * 2018/12/21 11:17
 */
public abstract class ElectingScheduler extends DisposingScheduler {
    private static final String MASTERS_ROOT = SPRT + "masters";
    private final Locker locker = Locker.create();
    private final EventListener<PlannedEvent> plannedEventListener = new PlannedEventListener();
    private Planner planner;
    private EventWatching masterVoteWatching;

    @Override
    protected void initializing(Context context) throws InitializingException {
        super.initializing(context);

        // region 绑定规划师
        planner = planner != null
                ? planner
                : context.get(Planner.class);
        planner.initialize(context);
        // endregion
    }

    @Override
    protected void destroying() throws DestroyingException {
        super.destroying();

        planner.destroy();
        planner = null;
    }

    @Override
    protected void starting() throws StartingException {
        super.starting();

        // 参与选举
        try {
            masterVoteWatching = coordinator.elect(MASTERS_ROOT, new MasterVoteWatcher());
        } catch (CoordinatorException e) {
            throw new StartingException(e);
        }

        // 监听规划师的任务命令
        planner.addEventListener(plannedEventListener);
    }

    @Override
    protected void shutting() throws ShuttingException {
        super.shutting();

        planner.removeEventListener(plannedEventListener);

        try {
            masterVoteWatching.close();
        } catch (CoordinatorException e) {
            throw new ShuttingException(e);
        }
    }

    /**
     * 上台，覆盖该方法后必须调用{@code super.onPowerAcquired()}
     *
     * @throws Exception 异常
     */
    protected void onPowerAcquired() throws Exception {

    }

    /**
     * 下台，覆盖该方法后必须调用{@code super.onPowerReleased()}
     *
     * @throws Exception 异常
     */
    protected void onPowerReleased() throws Exception {

    }

    /**
     *
     */
    private class PlannedEventListener implements EventListener<PlannedEvent> {

        @Override
        public void onListened(PlannedEvent event) throws Exception {
            Task task = event.getTask();
            long time = event.getTime();
            schedule(task, time);
        }
    }

    private class MasterVoteWatcher implements VoteWatcher {

        @Override
        public void onMyselfElected(Coordinator coordinator) throws Exception {
            try {
                // 如果当选为领导者，重启任务规划师
                planner.start();

                onPowerAcquired();

                // 锁住当前线程
                locker.acquire();
            } finally {
                // 方法返回时将失去领导权，暂停任务规划师
                planner.pause();
            }
        }

        @Override
        public boolean onStatusChanged(Coordinator coordinator, ConnStatus connStatus) throws Exception {
            if (!connStatus.connected) {
                // 暂停任务规划师
                planner.pause();

                onPowerReleased();

                // 释放领导权占用锁
                locker.release();
            }
            // 如果连接断开，强制释放领导权
            return connStatus.connected;
        }
    }

    public Planner getPlanner() {
        return planner;
    }

    public void setPlanner(Planner planner) {
        this.planner = planner;
    }
}
